home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_35 / gus.c < prev    next >
C/C++ Source or Header  |  1995-01-01  |  16KB  |  776 lines

  1. /*
  2.  
  3.   GUS.C
  4.  
  5.   Michael Chen
  6.   mchen@cs.psu.edu
  7.   4/18/1993
  8.  
  9.   See the included .TXT file for terms and other information.
  10.  
  11.   Note that when playing back 16-bit samples, the start and end positions
  12.   are measured in 16-bit words, not bytes!
  13.  
  14. */
  15.  
  16. #include "gus.h"
  17. #include <stdio.h>
  18. #include <dos.h>
  19.  
  20. int GUSBase;
  21. int GUSMixer;
  22. int GUSStatus;
  23. int GUSTimerControl;
  24. int GUSTimerData;
  25. int GUSIRQDMAControl;
  26. int GUSMIDIControl;
  27. int GUSMIDIData;
  28. int GUSVoice;
  29. int GUSCommand;
  30. int GUSDataLo;
  31. int GUSDataHi;
  32. int GUSDRAMIO;
  33. int GUSCurrentVoice = -1;
  34. int GUSVoices = MINVOICES;
  35.  
  36. byte GUSFreqDivisorTable[MAXVOICES+1] =
  37. /*
  38.   Divisor table when setting voice frequency, based on number of voices.
  39.   Remember, minimum of 14 active voices (though divisors given for 8 and up).
  40. */
  41.   { -1, -1, -1, -1, -1, -1, -1, -1, 74, 66, 60, 54, 50, 46, 43, 40, 37,
  42.     35, 33, 31, 30, 28, 27, 26, 25, 24, 23, 22, 21, 20, 20, 19, 18 };
  43.  
  44.  
  45. void GUSDelay()
  46. /*
  47.   Waits for GUS. (from Ultradox 2.0)
  48. */
  49.   {
  50.   int i;
  51.  
  52.   for (i=0; i<7; i++)
  53.     inportb(0x300);
  54.   }
  55.  
  56. void GUSReset()
  57. /*
  58.   Resets GUS. (from Ultradox 2.0)
  59. */
  60.   {
  61.   int i;
  62.  
  63.   /* Force routines to select voice explicitly first time */
  64.   GUSCurrentVoice = -1;
  65.  
  66.   /* Put GUS in initialization mode */
  67.   GUS_SetCommand(G_Initialize);
  68.   outportb(GUSDataHi,0);
  69.   GUSDelay();
  70.   GUSDelay();
  71.  
  72.   /* Take GUS out of initialization mode */
  73.   GUS_SetCommand(G_Initialize);
  74.   outportb(GUSDataHi,1);
  75.   GUSDelay();
  76.   GUSDelay();
  77.  
  78.   /* Ramp voices to 0 --- doesn't work yet */
  79. /*
  80.   GUSShutUp();
  81. */
  82.  
  83.   /* Clear DMA control */
  84.   GUS_SetCommand(G_DMAControl);
  85.   outportb(GUSDataHi,0);
  86.  
  87.   /* Clear timer control */
  88.   GUS_SetCommand(G_TimerControl);
  89.   outportb(GUSDataHi,0);
  90.  
  91.   /* Clear sample control */
  92.   GUS_SetCommand(G_SampleControl);
  93.   outportb(GUSDataHi,0);
  94.  
  95.   /* Set number of voices to minimum. */
  96.   GUSSetVoices(MINVOICES);
  97.  
  98.   /* Clear pending DMA control */
  99.   GUS_SetCommand(G_DMAControl);
  100.   inportb(GUSDataHi);
  101.  
  102.   /* Clear pending timer control */
  103.   GUS_SetCommand(G_TimerControl);
  104.   inportb(GUSDataHi);
  105.  
  106.   /* Clear pending sample control */
  107.   GUS_SetCommand(G_SampleControl);
  108.   inportb(GUSDataHi);
  109.  
  110.   /* Reset voices */
  111.   for (i=0; i<MAXVOICES; i++)
  112.     {
  113.     /* Select voice */
  114.     GUSSelectVoice(i);
  115.  
  116.     /* Stop voice */
  117.     GUSStopVoice(i);
  118.  
  119.     /* Turn off volume ramp */
  120.     GUSStopRamp(i);
  121.  
  122.     /* Set to zero volume */
  123.     GUSSetVolume(i,0);
  124.  
  125.     /* Set to center pan */
  126.     GUSSetVoiceBalance(0,P_Center);
  127.     }
  128.  
  129.   /* Clear pending DMA control */
  130.   GUS_SetCommand(G_DMAControl);
  131.   inportb(GUSDataHi);
  132.  
  133.   /* Clear pending sample control */
  134.   GUS_SetCommand(G_SampleControl);
  135.   inportb(GUSDataHi);
  136.  
  137.   /* Unknown read from IRQ status (?) */
  138.   GUS_SetCommand(G_IRQStatus);
  139.   inportb(GUSDataHi);
  140.  
  141.   /* Do something to initialization register (?) */
  142.   GUS_SetCommand(G_Initialize);
  143.   outportb(GUSDataHi,7);
  144.  
  145.   /* Set mixer to default (line-in and output on, mic-in off) */
  146.   GUSSetMixer(M_OutputOn|M_LineInOn|M_MicInOff);
  147.   }
  148.  
  149. byte GUSPeek(longword addr)
  150. /*
  151.   Peeks at value from GUS DRAM (long address).
  152. */
  153.   {
  154.   return GUS_Peek(addr >> 16,addr & 0xFFFF);
  155.   }
  156.  
  157. void GUSPoke(longword addr, byte val)
  158. /*
  159.   Pokes value to GUS DRAM (long address).
  160. */
  161.   {
  162.   GUS_Poke(addr >> 16,addr & 0xFFFF,val);
  163.   }
  164.  
  165. byte GUSPokePeek(longword addr, byte val)
  166. /*
  167.   Pokes value to GUS DRAM (long address), then immediately peeks same.
  168. */
  169.   {
  170.   return GUS_PokePeek(addr >> 16,addr & 0xFFFF,val);
  171.   }
  172.  
  173. static byte GUS_Peek(byte addrhi, word addrlo)
  174. /*
  175.   Peeks at value from GUS DRAM.
  176. */
  177.   {
  178.   GUS_SetCommand(G_SetDRAMLo);
  179.   outport(GUSDataLo,addrlo);
  180.   GUS_SetCommand(G_SetDRAMHi);
  181.   outportb(GUSDataHi,addrhi);
  182.   return GUS_ReadDRAMIO();
  183.   }
  184.  
  185. static void GUS_Poke(byte addrhi, word addrlo, byte val)
  186. /*
  187.   Pokes value to GUS DRAM.
  188. */
  189.   {
  190.   GUS_SetCommand(G_SetDRAMLo);
  191.   outport(GUSDataLo,addrlo);
  192.   GUS_SetCommand(G_SetDRAMHi);
  193.   outportb(GUSDataHi,addrhi);
  194.   GUS_SetDRAMIO(val);
  195.   }
  196.  
  197. static byte GUS_PokePeek(byte addrhi, word addrlo, byte val)
  198. /*
  199.   Pokes value to GUS DRAM, then immediately peek from same location.
  200. */
  201.   {
  202.   GUS_SetCommand(G_SetDRAMLo);
  203.   outport(GUSDataLo,addrlo);
  204.   GUS_SetCommand(G_SetDRAMHi);
  205.   outportb(GUSDataHi,addrhi);
  206.   outportb(GUSDRAMIO,val);
  207.   return GUS_ReadDRAMIO();
  208.   }
  209.  
  210. int ProbeGUS()
  211. /*
  212.   Probes to see if GUS exists at current base address. (from Ultradox 2.0)
  213. */
  214.   {
  215.   byte testbyte = 0xAA;
  216.   byte test1;
  217.  
  218.   GUS_SetCommand(G_Initialize);
  219.   outportb(GUSDataHi,0);
  220.   GUSDelay();
  221.   GUSDelay();
  222.   GUS_SetCommand(G_Initialize);
  223.   outportb(GUSDataHi,1);
  224.   GUSDelay();
  225.   GUSDelay();
  226.   GUSPoke(0,testbyte);
  227.   GUSPoke(1,0xFF - testbyte);
  228.   test1 = GUSPeek(0);
  229.   GUS_SetCommand(G_Initialize);
  230.   outportb(GUSDataHi,0);
  231.   return (test1 == testbyte);
  232.   }
  233.  
  234. int DetectGUS()
  235. /*
  236.   Returns base address of GUS ports, or 0 if no GUS detected.
  237. */
  238.   {
  239.   for (GUSBase = 0x210; (GUSBase < 0x270); GUSBase += 0x10)
  240.     {
  241.     GUSMixer = GUSBase;
  242.     GUSStatus = GUSBase + 6;
  243.     GUSTimerControl = GUSBase + 8;
  244.     GUSTimerData = GUSBase + 9;
  245.     GUSIRQDMAControl = GUSBase + 0xB;
  246.     GUSMIDIControl = GUSBase + 0x100;
  247.     GUSMIDIData = GUSBase + 0x101;
  248.     GUSVoice = GUSBase + 0x102;
  249.     GUSCommand = GUSBase + 0x103;
  250.     GUSDataLo = GUSBase + 0x104;
  251.     GUSDataHi = GUSBase + 0x105;
  252.     GUSDRAMIO = GUSBase + 0x107;
  253.     if (ProbeGUS()) break;
  254.     }
  255.   if (GUSBase < 0x270)
  256.     return GUSBase;
  257.   else
  258.     return 0;
  259.   }
  260.  
  261. static void GUS_SelectVoice(byte voice)
  262. /*
  263.   Selects current GUS voice for subsequent commands.
  264. */
  265.   {
  266.   GUS_SetVoice(voice);
  267.   GUSCurrentVoice = voice;
  268.   }
  269.  
  270. void GUSSelectVoice(byte voice)
  271. /*
  272.   Changes current GUS voice for subsequent commands if necessary.
  273. */
  274.   {
  275.   if (GUSCurrentVoice != voice)
  276.     GUS_SelectVoice(voice);
  277.   }
  278.  
  279. void GUSStopVoice(byte voice)
  280. /*
  281.   Stops GUS voice.
  282. */
  283.   {
  284.   byte b;
  285.  
  286.   GUSSelectVoice(voice);
  287.   b = GUSReadVoiceMode(voice);
  288.   if (!(b & V_VoiceStopped))
  289.     {
  290.     b |= 3;
  291.     GUS_SetCommand(G_SetVoiceMode);
  292.     outportb(GUSDataHi,b);
  293.     }
  294.   }
  295.  
  296. void GUSStartVoice(byte voice)
  297. /*
  298.   Starts GUS voice.
  299. */
  300.   {
  301.   byte b;
  302.  
  303.   GUSSelectVoice(voice);
  304.   b = GUSReadVoiceMode(voice);
  305.   if (b & V_VoiceStopped)
  306.     {
  307.     b &= 0xFC;
  308.     GUS_SetCommand(G_SetVoiceMode);
  309.     outportb(GUSDataHi,b);
  310.     }
  311.   }
  312.  
  313. void GUSSetVoiceMode(byte voice, byte mode)
  314. /*
  315.   Sets GUS voice mode (not start/stop, though) directly.
  316. */
  317.   {
  318.   byte b;
  319.  
  320.   GUSSelectVoice(voice);
  321.   GUS_SetCommand(G_ReadVoiceMode);
  322.   b = inportb(GUSDataHi);
  323.   b &= 3;
  324.   b |= (mode & 0xFC);
  325.   GUS_SetCommand(G_SetVoiceMode);
  326.   outportb(GUSDataHi,b);
  327.   }
  328.  
  329. void GUSSetVoices(byte voices)
  330. /*
  331.   Sets number of voices for GUS.
  332. */
  333.   {
  334.   GUS_SetCommand(G_SetMaxVoice);
  335.   outportb(GUSDataHi,((voices-1) | G_VoiceMask));
  336.   GUSVoices = voices;
  337.   }
  338.  
  339. void GUSSetVoiceFreq(byte voice, word freq)
  340. /*
  341.   Sets GUS voice frequency, taking into account number of voices.
  342. */
  343.   {
  344.   GUSSelectVoice(voice);
  345.   GUS_SetCommand(G_SetVoiceFreq);
  346.   outport(GUSDataLo,freq/GUSFreqDivisorTable[GUSVoices]);
  347.   }
  348.  
  349. static void GUS_SetLoopStart(byte voice, word hi, word lo)
  350.   {
  351.   GUSSelectVoice(voice);
  352.   GUS_SetCommand(G_SetLoopStartLo);
  353.   outport(GUSDataLo,lo);
  354.   GUS_SetCommand(G_SetLoopStartHi);
  355.   outport(GUSDataLo,hi);
  356.   }
  357.  
  358. static void GUS_SetLoopEnd(byte voice, word hi, word lo)
  359.   {
  360.   GUSSelectVoice(voice);
  361.   GUS_SetCommand(G_SetLoopEndLo);
  362.   outport(GUSDataLo,lo);
  363.   GUS_SetCommand(G_SetLoopEndHi);
  364.   outport(GUSDataLo,hi);
  365.   }
  366.  
  367. static void GUS_SetPosition(byte voice, word hi, word lo)
  368.   {
  369.   GUSSelectVoice(voice);
  370.   GUS_SetCommand(G_SetPositionLo);
  371.   outport(GUSDataLo,lo);
  372.   GUS_SetCommand(G_SetPositionHi);
  373.   outport(GUSDataLo,hi);
  374.   }
  375.  
  376. void GUSSetLoopStart(byte voice, longword addr)
  377. /*
  378.   Sets loop start of voice.
  379. */
  380.   {
  381.   GUS_SetLoopStart(voice,addr << 9, addr >> 7);
  382.   }
  383.  
  384. void GUSSetLoopEnd(byte voice, longword addr)
  385. /*
  386.   Sets loop (sample) end of voice.
  387. */
  388.   {
  389.   GUS_SetLoopEnd(voice,addr << 9, addr >> 7);
  390.   }
  391.  
  392. void GUSSetPosition(byte voice, longword addr)
  393. /*
  394.   Sets position (sample begin) of voice.
  395. */
  396.   {
  397.   GUS_SetPosition(voice,addr << 9, addr >> 7);
  398.   }
  399.  
  400. longword GUSReadLoopEnd(byte voice)
  401. /*
  402.   Reads loop (sample) end of voice.
  403. */
  404.   {
  405.   longword l;
  406.  
  407.   GUSSelectVoice(voice);
  408.   GUS_SetCommand(G_ReadLoopEndLo);
  409.   l = ((longword)((word)inport(GUSDataLo)) & 0x1FFF) << 7;
  410.   GUS_SetCommand(G_ReadLoopEndHi);
  411.   l |= ((word)inport(GUSDataLo)) >> 9;
  412.   return l;
  413.   }
  414.  
  415. longword GUSReadLoopStart(byte voice)
  416. /*
  417.   Reads loop start of voice.
  418. */
  419.   {
  420.   longword l;
  421.  
  422.   GUSSelectVoice(voice);
  423.   GUS_SetCommand(G_ReadLoopStartLo);
  424.   l = ((longword)((word)inport(GUSDataLo)) & 0x1FFF) << 7;
  425.   GUS_SetCommand(G_ReadLoopStartHi);
  426.   l |= ((word)inport(GUSDataLo)) >> 9;
  427.   return l;
  428.   }
  429.  
  430. longword GUSReadPosition(byte voice)
  431. /*
  432.   Reads position (sample begin) of voice.
  433. */
  434.   {
  435.   longword l;
  436.  
  437.   GUSSelectVoice(voice);
  438.   GUS_SetCommand(G_ReadPositionLo);
  439.   l = ((longword)((word)inport(GUSDataLo)) & 0x1FFF) << 7;
  440.   GUS_SetCommand(G_ReadPositionHi);
  441.   l |= ((word)inport(GUSDataLo)) >> 9;
  442.   return l;
  443.   }
  444.  
  445. byte GUSReadVoiceMode(byte voice)
  446. /*
  447.   Reads mode of voice.
  448. */
  449.   {
  450.   GUSSelectVoice(voice);
  451.   GUS_SetCommand(G_ReadVoiceMode);
  452.   return inportb(GUSDataHi);
  453.   }
  454.  
  455. word GUSReadVoiceFreq(byte voice)
  456. /*
  457.   Reads frequency of voice.
  458. */
  459.   {
  460.   GUSSelectVoice(voice);
  461.   GUS_SetCommand(G_ReadVoiceFreq);
  462.   return inport(GUSDataLo) * GUSFreqDivisorTable[GUSVoices];
  463.   }
  464.  
  465. void GUSSetVolume(byte voice, word vol)
  466. /*
  467.   Sets volume of voice.
  468. */
  469.   {
  470.   GUSSelectVoice(voice);
  471.   GUS_SetCommand(G_SetVolume);
  472.   outport(GUSDataLo,vol);
  473.   }
  474.  
  475. word GUSReadVolume(byte voice)
  476. /*
  477.   Reads volume of voice.
  478. */
  479.   {
  480.   GUSSelectVoice(voice);
  481.   GUS_SetCommand(G_ReadVolume);
  482.   return (word)inport(GUSDataLo);
  483.   }
  484.  
  485. void GUSSetVoiceBalance(byte voice, byte pan)
  486. /*
  487.   Sets pan of voice.
  488. */
  489.   {
  490.   GUSSelectVoice(voice);
  491.   GUS_SetCommand(G_SetVoiceBalance);
  492.   outportb(GUSDataHi,pan);
  493.   }
  494.  
  495. byte GUSReadVoiceBalance(byte voice)
  496. /*
  497.   Reads pan of voice.
  498. */
  499.   {
  500.   GUSSelectVoice(voice);
  501.   GUS_SetCommand(G_ReadVoiceBalance);
  502.   return inportb(GUSDataHi);
  503.   }
  504.  
  505. /*
  506.  
  507. void GUSSetDRAM(longword addr, void* buf, longword len)
  508.  
  509.   Set region of GUS DRAM starting at addr, len bytes long to buf.
  510.   Not yet optimized for speed.
  511.  
  512.   {
  513.   byte* bp;
  514.  
  515.   bp = buf;
  516.   while (len-- > 0)
  517.     {
  518.     GUSPoke(addr++,*bp++);
  519.     }
  520.   }
  521.  
  522. */
  523.  
  524. void GUSSetDRAM(longword addr, void* buf, longword len)
  525. /*
  526.   Set region of GUS DRAM starting at addr, len bytes long to buf.
  527.   (Supposedly) partially optimized for speed.
  528. */
  529.   {
  530.   byte* bp;
  531.   byte addrhi;
  532.   word addrlo;
  533.  
  534.   bp = buf;
  535.   addrhi = addr >> 16;
  536.   addrlo = addr & 0xFFFF;
  537.  
  538.   GUS_SetCommand(G_SetDRAMHi);
  539.   outportb(GUSDataHi,addrhi);
  540.   GUS_SetCommand(G_SetDRAMLo);
  541.  
  542.   while (len-- > 0)
  543.     {
  544.     outport(GUSDataLo,addrlo++);
  545.     GUS_SetDRAMIO(*bp++);
  546.     if (!addrlo)
  547.       {
  548.       GUS_SetCommand(G_SetDRAMHi);
  549.       outportb(GUSDataHi,addrhi);
  550.       GUS_SetCommand(G_SetDRAMLo);
  551.       }
  552.     }
  553.   }
  554.  
  555. /*
  556.  
  557. void GUSReadDRAM(longword addr, void* buf, longword len)
  558.  
  559.   Read region of GUS DRAM starting at addr, len bytes long to buf.
  560.   Not yet optimized for speed.
  561.  
  562.   {
  563.   byte* bp;
  564.  
  565.   bp = buf;
  566.   while (len-- > 0)
  567.     {
  568.     *bp++ = GUSPeek(addr++);
  569.     }
  570.   }
  571.  
  572. */
  573.  
  574. void GUSReadDRAM(longword addr, void* buf, longword len)
  575. /*
  576.   Read region of GUS DRAM starting at addr, len bytes long to buf.
  577.   (Supposedly) partially optimized for speed.
  578. */
  579.   {
  580.   byte* bp;
  581.   byte addrhi;
  582.   word addrlo;
  583.  
  584.   bp = buf;
  585.   addrhi = addr >> 16;
  586.   addrlo = addr & 0xFFFF;
  587.  
  588.   GUS_SetCommand(G_SetDRAMHi);
  589.   outportb(GUSDataHi,addrhi);
  590.   GUS_SetCommand(G_SetDRAMLo);
  591.  
  592.   while (len-- > 0)
  593.     {
  594.     outport(GUSDataLo,addrlo++);
  595.     *bp++ = GUS_ReadDRAMIO();
  596.     if (!addrlo)
  597.       {
  598.       GUS_SetCommand(G_SetDRAMHi);
  599.       outportb(GUSDataHi,addrhi);
  600.       GUS_SetCommand(G_SetDRAMLo);
  601.       }
  602.     }
  603.   }
  604.  
  605. void GUSFillDRAM(longword addr, byte b, longword len)
  606. /*
  607.   Set region of GUS DRAM starting at addr, len bytes long to b.
  608.   (Supposedly) partially optimized for speed.
  609. */
  610.   {
  611.   byte addrhi;
  612.   word addrlo;
  613.  
  614.   addrhi = addr >> 16;
  615.   addrlo = addr & 0xFFFF;
  616.  
  617.   GUS_SetCommand(G_SetDRAMHi);
  618.   outportb(GUSDataHi,addrhi);
  619.   GUS_SetCommand(G_SetDRAMLo);
  620.  
  621.   while (len-- > 0)
  622.     {
  623.     outport(GUSDataLo,addrlo++);
  624.     GUS_SetDRAMIO(b);
  625.     if (!addrlo)
  626.       {
  627.       GUS_SetCommand(G_SetDRAMHi);
  628.       outportb(GUSDataHi,addrhi);
  629.       GUS_SetCommand(G_SetDRAMLo);
  630.       }
  631.     }
  632.   }
  633.  
  634. void GUSSetVolumeRampRate(byte voice, byte incr, byte scale)
  635. /*
  636.   Set voice's volume ramp rate.  Scale updates as follows:
  637.       00 - every access
  638.       01 - every 8th access
  639.       10 - every 64th access
  640.       11 - every 512th access
  641.   Advice from Ultradox 2.0: use increments of 8 or less; don't ramp to either
  642.   extreme (below 636, above 4032)
  643. */
  644.   {
  645.   GUSSelectVoice(voice);
  646.   GUS_SetCommand(G_SetVolumeRampRate);
  647.   outportb(GUSDataHi,(incr & 0x3f) | ((scale & 3) << 6));
  648.   }
  649.  
  650. byte GUSReadVolumeRampRate(byte voice)
  651.   {
  652.   GUSSelectVoice(voice);
  653.   GUS_SetCommand(G_SetVolumeRampRate);
  654.   return inportb(GUSDataHi);
  655.   }
  656.  
  657. void GUSSetVolumeRampStart(byte voice, word vol)
  658.   {
  659.   GUSSelectVoice(voice);
  660.   GUS_SetCommand(G_SetVolumeRampStart);
  661.   outportb(GUSDataHi,(vol >> 8));
  662.   }
  663.  
  664. void GUSSetVolumeRampEnd(byte voice, word vol)
  665.   {
  666.   GUSSelectVoice(voice);
  667.   GUS_SetCommand(G_SetVolumeRampEnd);
  668.   outportb(GUSDataHi,(vol >> 8));
  669.   }
  670.  
  671. word GUSReadVolumeRampStart(byte voice)
  672.   {
  673.   GUSSelectVoice(voice);
  674.   GUS_SetCommand(G_ReadVolumeRampStart);
  675.   return ((word)inportb(GUSDataHi)) << 8;
  676.   }
  677.  
  678. word GUSReadVolumeRampEnd(byte voice)
  679.   {
  680.   GUSSelectVoice(voice);
  681.   GUS_SetCommand(G_ReadVolumeRampEnd);
  682.   return ((word)inportb(GUSDataHi)) << 8;
  683.   }
  684.  
  685. void GUSSetVolumeControl(byte voice, byte mode)
  686.   {
  687.   GUSSelectVoice(voice);
  688.   GUS_SetCommand(G_SetVolumeControl);
  689.   outportb(GUSDataHi,mode);
  690.   }
  691.  
  692. byte GUSReadVolumeControl(byte voice)
  693.   {
  694.   GUSSelectVoice(voice);
  695.   GUS_SetCommand(G_ReadVolumeControl);
  696.   return inportb(GUSDataHi);
  697.   }
  698.  
  699. static int GUSMixerState = 0;
  700.  
  701. void GUSSetMixer(byte mode)
  702.   {
  703.   GUSMixerState = mode;
  704.   GUS_SetMixer(mode);
  705.   }
  706.  
  707. byte GUSReadMixer()
  708.   {
  709.   return GUSMixerState;
  710.   }
  711.  
  712. void GUSStopRamp(byte voice)
  713. /*
  714.   Stops GUS voice ramp.
  715. */
  716.   {
  717.   byte b;
  718.  
  719.   GUSSelectVoice(voice);
  720.   b = GUSReadVolumeControl(voice);
  721.   if (!(b & V_RampStopped))
  722.     {
  723.     b |= 3;
  724.     GUS_SetCommand(G_SetVolumeControl);
  725.     outportb(GUSDataHi,b);
  726.     }
  727.   }
  728.  
  729. void GUSStartRamp(byte voice)
  730. /*
  731.   Starts GUS voice ramp.
  732. */
  733.   {
  734.   byte b;
  735.  
  736.   GUSSelectVoice(voice);
  737.   b = GUSReadVolumeControl(voice);
  738.   if (b & V_RampStopped)
  739.     {
  740.     b &= 0xFC;
  741.     GUS_SetCommand(G_SetVolumeControl);
  742.     outportb(GUSDataHi,b);
  743.     }
  744.   }
  745.  
  746. void GUSShutUp()
  747.   {
  748.   int i;
  749.   word vol;
  750.   byte incr;
  751.  
  752.   for (i = 0; i < MAXVOICES; i++)
  753.     {
  754.     GUSSelectVoice(i);
  755.     vol = GUSReadVolume(i);
  756.     if (vol > 0)
  757.       {
  758.       GUSSetVolumeRampStart(i,vol);
  759.       GUSSetVolumeRampEnd(i,0);
  760.       GUSSetVolumeRampRate(i,1,R_Every1);
  761.       GUSSetVolumeControl(i,V_StartRamp|V_Decreasing);
  762.       GUSStartRamp(i);
  763.  
  764.       /* code for ramps seems not to work; no change in volume */
  765.       while ((incr = GUSReadVolumeControl(i) & V_RampStopped)
  766.             != V_RampStopped)
  767.         {
  768.         vol = GUSReadVolume(i);
  769.         if (vol >> 12 == 0) break; /* quiet enough */
  770.         printf("vol 0x%04x mode 0x%02x\r",vol,incr);
  771.         }
  772.       }
  773.     }
  774.   }
  775.  
  776.